package net.feling.mcloud.connection;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Log;
import net.feling.mcloud.filter.UserCodecFactory;
import net.feling.mcloud.utils.DefaultClientHandler;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketConnector;
import java.net.InetSocketAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class ConnectorManager {

    private static final String TAG = "ConnectorManager";

    private NioSocketConnector connector;
    private ConnectFuture connectFuture;
    private IoSession ioSession;
    private Context context;
    private ExecutorService executor;

    private ConnectorManager(Context context) {
        this.context = context;
        executor = Executors.newFixedThreadPool(3);
        connector = new NioSocketConnector();
        connector.setConnectTimeoutMillis(10 * 1000);
        connector.getSessionConfig().setBothIdleTime(60);
        connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new UserCodecFactory()));
        connector.getFilterChain().addLast("logger", new LoggingFilter());
        connector.setHandler(new DefaultClientHandler());
    }

    private static ConnectorManager manager;

    /**
     * 单例模式
     * @param context
     * @return
     */
    public synchronized static ConnectorManager getInstance(Context context) {
        if (manager == null) {
            manager = new ConnectorManager(context);
        }
        return manager;
    }

    private synchronized void innerConnect(final String serverHost, final int serverPort) {
        try {
            if (isConnected()) {
                return;
            }

            // 初始化服務器連接信息
            InetSocketAddress remoteAddress = new InetSocketAddress(serverHost, serverPort);
            connectFuture = connector.connect(remoteAddress);
            connectFuture.awaitUninterruptibly();
            ioSession = connectFuture.getSession();

        } catch (Exception e) {
            e.printStackTrace();
            Log.d(TAG, "-------------->连接服务器失败" + serverHost + ":" + serverHost);
            //TODO some Broadcast work here
        }
    }

    public void connect(final String serverHost, final int serverPort) {
        if (!isNetWorkAvailable(context)) {
            //TODO some Broadcast work here
            return;
        }

        Future<?> future = executor.submit(new Runnable() {
            @Override
            public void run() {
                innerConnect(serverHost, serverPort);
            }
        });

        try {
            if (future.get() == null) {
                connect(serverHost, serverPort);
            }
        } catch (Exception e) {
            e.printStackTrace();
            connect(serverHost, serverPort);
        }
    }

    public void send() {

    }

    public void destroy() {
        if (manager.ioSession != null) {
            ioSession.close(false);
        }
        if (manager.connector != null && !manager.connector.isDisposed()) {
            manager.connector.dispose();
        }
        manager = null;
    }


    public void closeSession() {
        if (ioSession != null) {
            ioSession.close(false);
        }
    }

    public boolean isConnected() {
        if (ioSession == null || connector == null) {
            return false;
        }
        return ioSession.isConnected();
    }

    public boolean isNetWorkAvailable(Context context) {
        ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        if (connectivityManager == null) {
            return false;
        } else {
            NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
            if (networkInfo.getState() == NetworkInfo.State.CONNECTED) {
                return true;
            }
        }
        return false;
    }
}
